package gov.nasa.anml.lifted;

import java.util.*;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.PDDL.Expression;
import gov.nasa.anml.PDDL.FloatLiteral;
import gov.nasa.anml.PDDL.Function;
import gov.nasa.anml.PDDL.FunctionReference;
import gov.nasa.anml.PDDL.Predicate;
import gov.nasa.anml.PDDL.PredicateReference;
import gov.nasa.anml.utility.*;
import static gov.nasa.anml.lifted.IdentifierCode.*;

public class ConstantFunction<T extends SimpleObject<? super T>> extends Term<T,SimpleVoid> implements ConstantExpression<T> {
	public Type<T> type;
	
	public ArrHashMap<SimpleObject<?>[],ConstantExpression<T>> init;
	//public Statement initializer;
	
	public ConstantFunction() {}
	public ConstantFunction(String n) {name=new SimpleString(n);}
	public ConstantFunction(SimpleString n) {name=n;}
	public ConstantFunction(SimpleString n, Type<T> t) {name=n;type=t;}

	public TypeCode typeCode() {
		return type.typeCode();
	}
	public IdentifierCode idCode() {
		return ConstantFunction;
	}
	
	transient PDDL.Predicate boolPDDL;
	transient PDDL.Function floatPDDL;

	private Object asPDDLExpression;
	
	public void translateDecl(PDDL pddl,Interval unit) {
		int length = pddl.bufAppend(name);
		String nameString = pddl.bufToString();
		pddl.bufReset(length);
		
		switch(typeCode()) {
		case Boolean:
			if (boolPDDL != null)
				return;
			boolPDDL = pddl.new Predicate(nameString);
			boolPDDL.context.addAll(pddl.context);
			for (Parameter<?> p : parameters.table) {
				p.translateDecl(pddl,boolPDDL);
			}
			pddl.predicates.add(boolPDDL);
			asPDDLExpression = boolPDDL.trivialRef();
			// initialization...?
			break;
		case Float:
			if (floatPDDL != null)
				return;
			floatPDDL = pddl.new Function(nameString);
			floatPDDL.context.addAll(pddl.context);
			for (Parameter<?> p : parameters.table) {
				p.translateDecl(pddl,floatPDDL);
			}
			pddl.functions.add(floatPDDL);
			asPDDLExpression = floatPDDL.trivialRef();
			break;
		case Integer:
			// be nice by relaxing integers to floats in the compilation to PDDL
			if (floatPDDL != null) // shouldn't happen...
				return;
			// make sure all future references see this as a float
			type = (Type<T>) Unit.floatType; 
			floatPDDL = pddl.new Function(nameString);
			floatPDDL.context.addAll(pddl.context);
			for (Parameter<?> p : parameters.table) {
				p.translateDecl(pddl,floatPDDL);
			}
			pddl.functions.add(floatPDDL);
			asPDDLExpression = floatPDDL.trivialRef();
			break;
		default:
			System.err.println("Unsupported type: " + this.type + " in: " + this + ".");
		}
	}
	
	public History<SimpleVoid> storage(State p, State c) {
		return null;
	}
	public T value(State s) {
		return null;
	}
	public boolean apply(State p, int contextID, State c) {
		return false;
	}
	
	// cannot occur as expression or statement; see ConstantFunctionReference instead
	
}
